<?php

declare(strict_types=1);

namespace App\Controller\Admin\Common;

use App\Entity\Goods;
use App\Entity\Order;
use App\Event\LogDescriptionEvent;
use App\Message\Order as MessageOrder;
use App\Message\SmsLog;
use App\Service\RedisService;
use App\Utils\Annotation\ApiName;
use App\Utils\Annotation\ApiParam;
use App\Utils\Traits\ControllerTrait;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

/**
 * Class DefaultController
 * @package App\Controller\Admin\Common
 * @ApiName(name="默认控制器")
 * @Route("/admin/common/default", name="admin-common-default")
 */
class DefaultController extends AbstractController {
    use ControllerTrait;

    private $redis;
    private $logger;
    private $cache;
    private $event_dispatcher;
    private $lock_factory;

    public function __construct (RedisService $client, LoggerInterface $apiLogger, CacheInterface $cache, EventDispatcherInterface $eventDispatcher, LockFactory $lockFactory) {
        $this->redis = $client->redis;
        $this->logger = $apiLogger;
        $this->cache = $cache;
        $this->event_dispatcher = $eventDispatcher;
        $this->lock_factory = $lockFactory;
    }

    /**
     * @ApiName(name="message示例", description="symfony message 示例代码")
     * @Route("/", methods={"GET"}, name="index")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function index (Request $request) {
        $this->dispatchMessage(new SmsLog('这是一条测试信息'));
        $this->dispatchMessage(new MessageOrder(10001));
        return json_success('work!');
    }

    /**
     * @ApiName(name="redis示例")
     * @Route("/cache/set", methods={"GET"}, name="cache-data")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function getRedisCacheData (Request $request) {
        $this->redis->setnx('key', '123');
        $this->redis->expire('key', 10);
        $this->redis->set('app', 999);
        return json_success($this->redis->get('app'));
    }

    /**
     * @ApiName(name="cache示例")
     * @Route("/cache/adapter/set", methods={"GET"}, name="cache-adapter-data")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     * @throws \Psr\Cache\InvalidArgumentException
     */
    public function getCacheDataByAdapter (Request $request) {
        $value = $this->cache->get('my_cache_key', function (ItemInterface $item) {
            $item->expiresAfter(120);
            return 'test cache value';
        }, 1.0);
        return json_success($value);
    }

    /**
     * @ApiName(name="事件派遣示例")
     * @Route("/event", methods={"GET"}, name="event")
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     * @throws \Exception
     */
    public function doEventDemo () {
        $this->event_dispatcher->dispatch(new LogDescriptionEvent('default controller 随机数 - '), LogDescriptionEvent::NAME);
        return json_success('event working');
    }

    /**
     * @ApiName(name="lock组件示例，防止超卖")
     * @ApiParam(name="goods_id", type="integer", comment="商品ID", require=true)
     * @ApiParam(name="number", type="integer", comment="数量", require=true)
     * @Route("/lock-factory", methods={"POST"}, name="lock-factory")
     * @param Request $request
     */
    public function lockFactory (Request $request) {
        $params = $this->onlyDeclare($request);
        $key = 'goods:id:'.$params['goods_id'];
        $lock = $this->lock_factory->createLock($key);
        if (!$lock->acquire()) {
            return json_failure('系统繁忙，稍后尝试');
        }
        $goods = $this->getDoctrine()->getRepository(Goods::class)->find($params['goods_id']);
        if (!$goods) {
            return json_failure('商品不存在');
        }
        if ($goods->getStock() == 0) {
            return json_failure('商品已售罄');
        }
        if ($goods->getStock() < $params['number']) {
            return json_failure('商品库存不足');
        }
        $this->getEntityManage()->beginTransaction();
        try {
            $order = new Order();
            $order->setGoodsId($goods->getId());
            $order->setNumber($params['number']);
            $goods->setStock($goods->getStock() - $params['number']);
            $this->getEntityManage()->persist($order);
            $this->getEntityManage()->persist($goods);
            $this->getEntityManage()->flush();
            $this->getEntityManage()->commit();
            return json_success('下单成功');
        } catch (\Exception $e) {
            $this->getEntityManage()->rollback();
            return json_failure('下单失败：'.$e->getMessage());
        } finally {
            $lock->release();
        }
    }
}